<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>前端文件上传</title>
    <style>
        .input-container {
            position: relative;
            width: 140px;
            height: 100px;
            margin: 10px 0;
        }
        .input-box {
            height: 100%;
            border: 1px solid #dce3e8;
            border-radius: 6px;
            color: #8c92a4;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 12px;
        }
        #file:hover {
            cursor: pointer;
            box-shadow: 4px 4px 6px rgab(#8c92a4, 0.8);
        }
        #file {
            opacity: 0;
            position: absolute;
            height: 100%;
            width: 100%;
            top: 0;
            left: 0;
        }
        .submit {
            background: transparent;
            border: 1px solid #dce3e8;
            border-radius: 6px;
            width: 140px;
            height: 24px;
            cursor: pointer;
        }
        .submit:focus {
            outline: none;
        }

        #preview {
            display: flex;
            flex-wrap: wrap;
        }
        .preview__item {
            margin: 10px;
            border: 1px solid gray;
            width: 180px;
        }
        .preview__img {
            width: 100%;
            height: 180px;
        }
        .step {
            display: block;
            transition-duration: 0.5s;
        }
        .red {
            background: red;
        }
        .green {
            background: green;
        }
    </style>
</head>
<body>
    <h2>文件选择</h2>
    <div class="input-container">
        <div class="input-box">
            选择文件
        </div>
        <input type="file" id="file" multiple onchange="showPreview()"/>
    </div>
    <button class="submit" onclick="uploadImg()">上传</button>
    

    <h2>文件预览</h2>
    <div id="preview">
    </div>

    <script>
        // 最早的文件上传是通过 form 的 type = multipart/form-data 进行上传的
        // 后来新增的 FormData 也可以模拟表单上传文件


        // 实现多文件上传并添加预览和上传进度，和中断上传的操作
        const MAX_FILES_LENGTH = 100
        const uploadList = []
        const previewBox = document.getElementById('preview')

        function showPreview() {
            previewBox.innerHTML = ''

            const fileList = document.getElementById('file').files
            if (fileList.length > MAX_FILES_LENGTH) {
                alert(`最多同时上传${MAX_FILES_LENGTH}个文件！`)
                return
            }
            for (let file of fileList) {
                if (!/^image\//.test(file.type)) {
                    continue
                }
                
                const item = document.createElement('div')
                item.classList = 'preview__item'
                const img = document.createElement('img')
                img.classList = 'preview__img'
                img.src = URL.createObjectURL(file)
                img.onload = function () {
                    URL.revokeObjectURL(this.src)
                }

                const process = document.createElement('div')
                process.classList = 'preview__process'
                process.innerHTML = '<span class="red step"></span><button type="button">Abort</button>'

                item.appendChild(img)
                item.appendChild(process)
                previewBox.appendChild(item)

                // 使用uploadList可以避免上传文件时重复获取文件dom和对应的进度dom
                uploadList.push({
                    file,
                    item,
                    process
                })
            }
        }

        function uploadImg() {
            for (let item of uploadList) {
                sendRequest(item)
            }
        }

        function sendRequest({file, item, process}) {
            const step = process.firstElementChild
            const abort = process.getElementsByTagName('button')[0]

            abort.addEventListener('click', () => {
                if (xhr && xhr.readyState != 4) {
                    xhr.abort()
                }
            }, false)

            step.style.width = '0%'
            
            const formData = new FormData()
            formData.append('file', file)

            const xhr = new XMLHttpRequest()
            xhr.open('POST', 'http://localhost:3000/test', true)

            xhr.onreadystatechange = function() {
                if (xhr.readyState == 4 && xhr.status == 200) {
                    console.log(xhr.responseText)
                }
            }

            xhr.onprogress = updateProgress
            xhr.upload.onprogress = updateProgress

            function updateProgress (event) {
                if (event.lengthComputable) {
                    let precent = (event.loaded / event.total * 100).toFixed(2)
                    step.innerText = precent + '%'
                    step.style.width = precent + '%'
                    if (precent >= 90) {
                        step.classList.add('green')
                    }
                }
            }

            xhr.send(formData)
        }
    </script>
</body>
</html>